import express from 'express';
import { Validator } from '../common/validator';
import { simConfigSchema } from './validation/schema';
import { ValidationError } from 'joi';
import bodyParser from 'body-parser';
import * as _ from 'lodash';
import {
  getGatewayParseModelParamsApi, getNodeId, getOSSSimulationConfigFilePath,
  products
} from '../common/util';
import { getEnv, SimulationConfig } from '../common/simulator';
import { SimulationConfigCache } from '../common/cache';
import { simConfigServerApi } from '../common/httpSimConfigCommonApi';
import { simulator } from '.';
import path from 'path';
import axios from 'axios';
import {objectStorageService} from "../common/objectStorage";
import {buildSimulationJobDefinition} from "./simulationBuilder";
import {configurationService} from "../common/configService";


type ValidateResult = {error: ValidationError, value: SimulationConfig}

let app = express();
app.use(bodyParser.json({ limit: '50mb' }));

// 身份接口
app.get('/simulation/identity', (req, res) => {
  res.json({
    success: true,
    data: products.META
  });
});

// 保存或更新仿真设置
app.post('/simulation/config', async (req, res) => {
  console.info('simulation config req body: ', req.body);
  let simConfigCache = SimulationConfigCache.get();

  const validator = Validator.of(simConfigSchema);
  const { error, warning, value: simConfig } = validator.validate(req.body);
  console.info(`after validation, simConfig = ${JSON.stringify(simConfig)} `);
  
  if (error) {
    res.json({
      success: false,
      message: error.message
    });
    return;
  }

  if (simConfigCache) {
    _.mergeWith(simConfigCache, simConfig, customizer);
  } else {
    simConfigCache = simConfig;
  }
  
  console.log(`${JSON.stringify(simConfigCache)}`);

  try {
    const simConfigPath = getOSSSimulationConfigFilePath();
    await objectStorageService.putObject(configurationService.config.objectStorage.config.bucket, simConfigPath, JSON.stringify(simConfigCache));
    SimulationConfigCache.put(simConfigCache);
    res.json({
      success: true
    });

    if (!_.isEmpty(simConfig.input)) {
      simulator.emit('param:succeed', {
        input: simConfigCache.input || [],
        output: simConfigCache.output || [],
        nodeId: getNodeId()
      });
    }
  } catch (e) {
    res.json({
      success: false,
      message: e.message
    });

    simulator.emit('param:failed', e.message);
  }
});

// 从模型文件中解析输入输出参数
app.post('/simulation/resolve/param', async (req, res) => {
  const simConfig = SimulationConfigCache.get();
  if (!simConfig || !simConfig.model.file) {
    res.json({
      success: false,
      message: '模型文件不存在，请先上传模型文件'
    });
    return;
  }

  const entry = simConfig.model.entry;
  const modelType = simConfig.model.type;
  const modelFile = simConfig.model.file;
  const serverIdentity = simConfig.simServerIdentity;
  if (modelType === 'local' && !serverIdentity) {
    res.json({
      success: false,
      message: '请先选择仿真服务器'
    });
    return;
  }

  try {
    const filename = path.parse(modelFile).base;

    const gatewayParseParamApi = getGatewayParseModelParamsApi();
    const gatewayResult = await axios.post(gatewayParseParamApi, {
      product: products.META,
      type: modelType,
      serverIdentity: serverIdentity,
      modelPath: modelFile,
      entry: entry
    });

    const { success, message, data } = gatewayResult.data;

    res.json({
      success: success,
      message: message,
      data: data
    });

  } catch (e) {
    console.log('parse param from model error: ', e);
    res.json({
      success: false,
      message: e.message
    });
  }
});


// 运行仿真
app.get('/simulation/run', async (req, res) => {
  const simConfig = SimulationConfigCache.get();
  try {
    const jobDefinition = await buildSimulationJobDefinition( '{}', simConfig);
    const jobId = await simulator.run(jobDefinition, simConfig?.simServerIdentity?.join(';'));
    console.info(`simulation(businessId=${jobDefinition.businessId}, jobId=${jobId}) submitted`);
    simulator.emit('sim:info', jobId, jobDefinition);
    res.json({
      success: true
    });
  } catch (e) {
    res.json({
      success: false,
      message: e.message
    });
  }
});

app.get('/simulation/isStateful', async (req, res) => {
  res.json({
    success: true,
    data: false
  });
});

app.get('/simulation/solvers', async (req, res) => {
  res.json({
    success: true
  });
});


export function simServerInit() {
  app.listen(9900), () => {
    console.info('simulation server listening at 9900');
  };
}

simConfigServerApi(app);

function customizer(objValue, srcValue) {
  if (_.isPlainObject(srcValue) && _.isEmpty(srcValue)) {
    return {}; // 自定义逻辑，将空对象设置到目标对象中
  }
  if (_.isArray(objValue)) {
    return objValue = srcValue;
  }
}





